// Chris Williams and Kevin Preheim
// OS Design - Project 2

#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <fstream>
#include <list>
#include "simulator.h"
#ifndef BUDDY_H
	#define BUDDY_H
	#include "buddy.h"
#endif

#define STARTMEM 20971520
#define MAXALLOCATED 524288000
#define NUMTESTS 10000
#define SIZE 10485760

using namespace std;

int main(int argc, char *argv[]){

	int startMem;
	int maxAllocated;
	int numTests;

	// if arguments were set, initialize variables to arguments	
	if(argc == 4){
		startMem = atoi(argv[1]);
		maxAllocated = atoi(argv[2]);
		numTests = atoi(argv[3]);	
	}
	// else use defaults
	else{
		startMem = STARTMEM;
		maxAllocated = MAXALLOCATED;
		numTests = NUMTESTS;		
	}

	// timer variables
	timeval t1, t2;
	double elapsedTime;
	
	// open outfile for writing
	fstream outfile;
	outfile.open("output.csv", fstream::out | fstream::trunc);
	
	// keep doing more trials until we've tested up to maxAllocated
	while(startMem < maxAllocated){

		// create a simulator
		Simulator *simulator = new Simulator();
		list<Request> requests = simulator->generateRequests(numTests, startMem);
		list<Request>::iterator it;

		Block **BlockArray;
		BlockArray = new Block * [numTests];

		//**********************************************//
		//            TEST THE BUDDY SYSTEM             //
		//**********************************************//

		// start timer
		gettimeofday(&t1, NULL);

		// intialize buddy system with startMem bytes of memory
		Buddy *buddy = new Buddy(startMem);
		
		// perform allocations
		for(it = requests.begin(); it != requests.end(); it++){
			// allocate
			if((*it).type == 0){
				BlockArray[(*it).id] = buddy->my_malloc((*it).size);
			}
			// free
			else if((*it).type == 1){
				buddy->my_free(BlockArray[(*it).id]);
			}
		}

		// delete the buddy system
		delete(buddy);

		// stop timer
		gettimeofday(&t2, NULL);
		
		// compute and print the elapsed time in millisec
		elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0;      // sec to ms
		elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0;   // us to ms
		printf("Buddy system: performed %d allocation operations in %f milliseconds\n", numTests, elapsedTime);
		outfile << elapsedTime << ",";	
		
		//**********************************************//
		//                  TEST MALLOC                 //
		//**********************************************//

		void ** PtrArray;
		PtrArray = new void * [numTests];

		// start timer
		gettimeofday(&t1, NULL);
		
		// perform allocations
		for(it = requests.begin(); it != requests.end(); it++){
			// allocate			
			if((*it).type == 0){
				PtrArray[(*it).id] = malloc((*it).size);
			}
			// free
			else if((*it).type == 1){
				free(PtrArray[(*it).id]);
			}
		}	

		// stop timer
		gettimeofday(&t2, NULL);
		
		// compute and print the elapsed time in millisec
		elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0;      // sec to ms
		elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0;   // us to ms
		printf("System call: performed %d allocation operations in %f milliseconds\n", numTests, elapsedTime);
		outfile << elapsedTime << endl;

		// delete objects
		delete(simulator);
		delete [] BlockArray;
		delete [] PtrArray;
		requests.erase(requests.begin(), requests.end());

		// add 10 megabytes
		startMem += 10485760;
	}
	
	outfile.close();
	
	return 0;
}
